Skip to content

feat(telemetry): add telemetry support for user agent parsing#90

Open
BenjaminAbt wants to merge 10 commits intomainfrom
feature/add-fluentapi-and-telemetry
Open

feat(telemetry): add telemetry support for user agent parsing#90
BenjaminAbt wants to merge 10 commits intomainfrom
feature/add-fluentapi-and-telemetry

Conversation

@BenjaminAbt
Copy link
Member

@BenjaminAbt BenjaminAbt commented Dec 27, 2025

@BenjaminAbt BenjaminAbt requested a review from gfoidl December 27, 2025 15:17
Copy link
Contributor

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of the event source, I'd prefer to use OTel metrics via the meters.
Especially as we don't write to the event stream (which could be read e.g. via PerfView), and I don't think we need the diagnostic events.

internal void UserAgentPresent()
{
if (!IsEnabled()) return;
_userAgentPresent?.Increment();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we don't write an event, should we use metrics (via meter factory) instead?
I'd prefer the OTel metrics here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are too many projects that do not use OTEL - even I/we currently still use native app insights in almost all projects because OTEL features are missing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, with UseAzureMonitor I see metrics in Azure. What features are there missing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we would still enforce everybody to use OTEL as foundation... I am not happy with that.

Copy link
Contributor

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then OK.

@BenjaminAbt BenjaminAbt requested a review from gfoidl December 27, 2025 19:37
@BenjaminAbt
Copy link
Member Author

BenjaminAbt commented Dec 27, 2025

@gfoidl , I added a telemetry hub and exposed otel native meters and dotnet metrics.
I think I dont have added any overhead.

Copy link
Contributor

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the OTel attributes we should follow the semantic convention (now, because changing it later would be a breaking change).

Sorry for the delay.

@BenjaminAbt
Copy link
Member Author

@gfoidl no problem. I expected the delay, since it was the holidays. Happy New Year.

@BenjaminAbt
Copy link
Member Author

@gfoidl there is this note

When instruments are measuring durations, seconds (i.e. s) SHOULD be used.

does this really make sense? We have parse.duration which is always 0s because its way faster than 0s

@gfoidl
Copy link
Contributor

gfoidl commented Feb 2, 2026

does this really make sense? We have parse.duration which is always 0s because its way faster than 0s

Makes sense, but the value has to be given as floating point number. Then the tools to display should show it as ms or that like.

@BenjaminAbt BenjaminAbt requested a review from gfoidl February 5, 2026 11:58
Comment on lines +86 to +87
- `useragent-present` (counter)
- `useragent-missing` (counter)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `useragent-present` (counter)
- `useragent-missing` (counter)
- `user_agent.present` (counter)
- `user_agent.missing` (counter)

s_meter = meter ?? new Meter(MeterName);

s_cacheHit = s_meter.CreateCounter<long>(
name: "cache.hit",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "cache.hit",
name: "user_agent_parser.cache.hit",

?
Otherwise it's only "cache" and which one is meant in a typical app with several caches.

description: "MemoryCache cache hit");

s_cacheMiss = s_meter.CreateCounter<long>(
name: "cache.miss",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "cache.miss",
name: "user_agent_parser.cache.miss",

description: "MemoryCache cache miss");

s_cacheSize = s_meter.CreateObservableGauge<long>(
name: "cache.size",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "cache.size",
name: "user_agent_parser.cache.size",

Comment on lines +106 to +108
- `cache-hit` (counter)
- `cache-miss` (counter)
- `cache-size` (observable gauge)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `cache-hit` (counter)
- `cache-miss` (counter)
- `cache-size` (observable gauge)
- `user_agent_parser.cache.hit` (counter)
- `user_agent_parser.cache.miss` (counter)
- `user_agent_parser.cache.size` (observable gauge)

/// counter reports a correct value once a listener attaches.
/// </remarks>
[NonEvent]
internal static void ConcurrentCacheSizeSet(int size) => HttpUserAgentParserTelemetryState.SetConcurrentCacheSize(size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
internal static void ConcurrentCacheSizeSet(int size) => HttpUserAgentParserTelemetryState.SetConcurrentCacheSize(size);
internal static void CacheSizeSet(int size) => HttpUserAgentParserTelemetryState.SetConcurrentCacheSize(size);

.AddHttpUserAgentParser();
```

### ConcurrentDictionary cache
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### ConcurrentDictionary cache
### Cached parser

?
The CDN and even concurrent shouldn't be exposed, as they're details.

Comment on lines +62 to +64
- `cache-concurrentdictionary-hit` (incrementing)
- `cache-concurrentdictionary-miss` (incrementing)
- `cache-concurrentdictionary-size` (polling)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `cache-concurrentdictionary-hit` (incrementing)
- `cache-concurrentdictionary-miss` (incrementing)
- `cache-concurrentdictionary-size` (polling)
- `cache-hit` (incrementing)
- `cache-miss` (incrementing)
- `cache-size` (polling)

Comment on lines +93 to +97
- `parse-requests` (counter)
- `parse-duration` (histogram, ms)
- `cache-concurrentdictionary-hit` (counter)
- `cache-concurrentdictionary-miss` (counter)
- `cache-concurrentdictionary-size` (observable gauge)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update to current used names.


Core (`MyCSharp.HttpUserAgentParser`)

- `parse-requests`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to be updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add telemetry (aka event-counters)

2 participants